import { createApp } from 'vue';
import { GLOBAL_RELATIVE, GLOBAL_HIDDEN } from '@/constants/class';
import type { App, DirectiveBinding } from 'vue';

// 按钮loading组件
import btnLoading from '@/components/btnLoading/index.vue';
// 局部loading
import partLoading from '@/components/partLoading/index.vue';

// 插入节点
const append = (el: HTMLElement & { instance: any }) => {
	// 绝对定位与相对定位
	const position = ['absolute', 'relative', 'fixed'];
	// 获取 dom 样式
	const style = getComputedStyle(el);

	// 指令设置背景色与字体颜色
	el.instance.$el.style.backgroundColor = style.backgroundColor;
	el.instance.$el.style.color = style.color;

	// 向 dom 添加溢出隐藏
	el.classList.add(GLOBAL_HIDDEN);
	// 判断父元素是否设置定位
	if (!position.includes(style.position)) {
		// 未设置定位 则添加相对定位
		el.classList.add(GLOBAL_RELATIVE);
	}

	// 向el节点插⼊动态创建的 div 节点，内容就是我们的 loading 组件
	el.appendChild(el.instance.$el);
};
// 移除节点
const remove = (el: HTMLElement & { instance: any }) => {
	// 移除动态创建的 div 节点
	if (el.contains(el.instance.$el)) {
		el.removeChild(el.instance.$el);
	}
	// 移除类名
	el.classList.remove(GLOBAL_HIDDEN);
	el.classList.remove(GLOBAL_RELATIVE);
};

/**
 * loading 指令
 * @directive 按钮 loading（v-btn-loading="xxx"）
 */
const btnLoadingDirective = (app: App) => {
	// 按钮 loading（v-btn-loading="xxx"）
	app.directive('btn-loading', {
		mounted(el: HTMLElement & { instance: any }, binding: DirectiveBinding) {
			// 创建 loading 对象跟组件为我们写好的 loading 组件
			const app = createApp(btnLoading);

			// 动态创建⼀个div节点，将 loading 挂载在div上
			// 我们的 loading 组件将替换此 div 标签的 innerHTML
			const instance = app.mount(document.createElement('div'));

			// 因为在updated也需要⽤到 instance 所以将 instance 添加在 el 上
			// 在 updated中 通过el.instance 可访问到
			el.instance = instance;

			// v-btn-loading传过来的值储存在 binding.value 中
			if (binding.value) {
				// 向el节点插⼊动态创建的 div 节点，内容就是我们的 loading 组件
				append(el);
			}

			// 判断是否有 title 值
			if (binding.arg) {
				(instance as any).setTitle(binding.arg);
			}
		},
		updated(el: HTMLElement & { instance: any }, binding: DirectiveBinding) {
			// 如果value的值有改变，那么我们去判断进⾏操作
			// 三元表达式 true 插入 false 移除
			binding.value ? append(el) : remove(el);
		},
	});
	// 局部 loading（v-part-loading="xxx"）
	app.directive('part-loading', {
		mounted(el: HTMLElement & { instance: any }, binding: DirectiveBinding) {
			// 创建 loading 对象跟组件为我们写好的 loading 组件
			const app = createApp(partLoading);

			// 动态创建⼀个div节点，将 loading 挂载在div上
			// 我们的 loading 组件将替换此 div 标签的 innerHTML
			const instance = app.mount(document.createElement('div'));

			// 因为在updated也需要⽤到 instance 所以将 instance 添加在 el 上
			// 在 updated中 通过el.instance 可访问到
			el.instance = instance;

			// v-btn-loading传过来的值储存在 binding.value 中
			if (binding.value) {
				// 向el节点插⼊动态创建的 div 节点，内容就是我们的 loading 组件
				append(el);
			}
		},
		updated(el: HTMLElement & { instance: any }, binding: DirectiveBinding) {
			// 如果value的值有改变，那么我们去判断进⾏操作
			// 三元表达式 true 插入 false 移除
			binding.value ? append(el) : remove(el);
		},
	});
};

export default btnLoadingDirective;
